﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GCC.APIContainer.Utilities;
using GCC.Container.Abstracts;
using GCC.Container.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.DeviceServer.ApiModels.DeviceInfo;
using System.DeviceServer.Models;
using System.Net.Http;
using System.Net;
using System.Diagnostics;

namespace System.DeviceServer
{
    [ApiController]
    [Route("[controller]")]
    public class DeviceInfoServer : GCCAPIControllerBase
    {
        
        public DeviceInfoServer(AbsGCCContext context) : base(context)
        {

        }

        [HttpGet("pointnames")]
        public DataResponse<List<string>> GetAllPointNames()
        {
            var childNodeStr = GCCContext.GetConfigByPath(new string[] { GCCContext.PointName ?? "", "ChildNodes" });
            if (childNodeStr == null)
            { 
                return new DataResponse<List<string>>();
            }
            var childList = System.Text.Json.JsonSerializer.Deserialize<List<ChildNode>>(childNodeStr,
                LuanNiao.JsonConverterExtends.CommonSerializerOptions.CamelCaseChineseNameCaseInsensitive);

            if (childList == null)
            {
                return new DataResponse<List<string>>();
            }
            List<string> result = new List<string>();

            foreach (var item in childList)
            {
                result.Add(item.name); 
            }
            return HandleData(result);
        }

        [HttpGet("alldevinfos")]
        // [GCCAuth(allowOffline: true, roles: new string[] { "admin" })]
        public async Task<DataResponse<List<GetDeviceInfoResponse>>> GetAllNodeDevicesInfo()
        {
            HttpClient client = new HttpClient();
            List<string> urlList = new List<string>();
            var childNodeStr = GCCContext.GetConfigByPath(new string[] { GCCContext.PointName ?? "", "ChildNodes" });
            if (childNodeStr is not null)
            {
                var childList = System.Text.Json.JsonSerializer.Deserialize<List<ChildNode>>(childNodeStr,
                LuanNiao.JsonConverterExtends.CommonSerializerOptions.CamelCaseChineseNameCaseInsensitive);

                if (childList is not null)
                {
                    foreach (var item in childList)
                    {
                        urlList.Add(item.url);
                    }
                }
            }

            List<GetDeviceInfoResponse> res = new List<GetDeviceInfoResponse>();
            foreach (string item in urlList)
            {
                Console.WriteLine("lsltest current node:{0}",item);
                string _address = item + "/deviceinfoserver/devinfos";
                var task = client.GetAsync(_address);
                var rep = task.Result;

                var task2 = rep.Content.ReadAsStringAsync();
                string ret = task2.Result;
                Console.WriteLine("lsltest http res:{0}", ret);
                var info = System.Text.Json.JsonSerializer.Deserialize<DeviceInfoRet>(ret,
                LuanNiao.JsonConverterExtends.CommonSerializerOptions.CamelCaseChineseNameCaseInsensitive
                );
                if (info is not null)
                {
                    //result = info;
                    Console.WriteLine("lsltest http res:{0}", info.DataCount);
                    foreach (var data in info.Data)
                    {
                        GetDeviceInfoResponse tmp = new GetDeviceInfoResponse()
                        {
                            DevID = data.DevID.ToString(),
                            DevName = data.DevName,
                            DevTypeID = data.DevTypeID.ToString(),
                            Created = data.Created,
                            CreatedBy = data.CreatedBy,
                            Modified = data.Modified,
                            ModifiedBy = data.ModifiedBy,
                            Status = data.Status,
                            DevTypeName = data.DevTypeName,
                            DevTypeICON = data.DevTypeICON,
                            PointName = data.PointName,
                        };
                        res.Add(tmp);
                    }
                }
            }
            Console.WriteLine("lsltest GetAllNodeDevicesInfo url result.count:{0}", res.Count);
            var dbres = AbsEntrance.DBManager!.LocalDB!.Select<DeviceInfo>()
                .Count(out var count)
                .ToList();

            CacheItemSettings cacheSett = new CacheItemSettings();
            cacheSett.SaveToAll = true;

            var deviceTypeList = await DeviceCache.Instance.GetAllDevType();
            Console.WriteLine("lsltest GetAllNodeDevicesInfo deviceTypeList:{0}", deviceTypeList.Count);
            //List<GetDeviceInfoResponse> resultList = new List<GetDeviceInfoResponse>();
            var list = from a in deviceTypeList
                       join b in dbres on a.TypeID equals b.DevTypeID
                       select new
                       {
                           DevID = b.DevID,
                           DevName = b.DevName,
                           DevTypeID = b.DevTypeID,
                           Status = b.Status,
                           Created = b.Created,
                           CreatedBy = b.CreatedBy,
                           Modified = b.Modified,
                           ModifiedBy = b.ModifiedBy,
                           DevTypeName = a.TypeName,
                           DevTypeICON = a.TypeICON,
                           PointName = a.PointName,
                       };
            foreach (var item in list)
            {
                GetDeviceInfoResponse temp = new GetDeviceInfoResponse();
                temp.DevID = item.DevID.ToString();
                temp.DevName = item.DevName;
                temp.DevTypeID = item.DevTypeID.ToString();
                temp.Status = item.Status;
                temp.Created = item.Created;
                temp.CreatedBy = item.CreatedBy;
                temp.Modified = item.Modified;
                temp.ModifiedBy = item.ModifiedBy;
                temp.DevTypeName = item.DevTypeName;
                temp.DevTypeICON = item.DevTypeICON.ToString();
                temp.PointName = item.PointName;
                res.Add(temp);
            }
            Console.WriteLine("lsl test GetAllNodeDevicesInfo result.count:{0}", res.Count);

            return HandleData(res, res.Count);
        }
        

        [HttpGet("devinfos")]
        // [GCCAuth(allowOffline: true, roles: new string[] { "admin" })]
        public async Task<DataResponse<List<GetDeviceInfoResponse>>> GetAllDevicesInfo([FromQuery] GetDeviceInfoRequest request)
        { 
           // var bTime = DateTime.ParseExact(request.BeginCreated, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture);
            var resultList = GCCEntrance.DBManager!.LocalDB!.Select<DeviceInfo>()
                .WhereIf(!string.IsNullOrWhiteSpace(request.DevName), item => item.DevName.Contains(request.DevName!))
                .WhereIf(!string.IsNullOrWhiteSpace(request.DevID), item => item.DevID == long.Parse(request.DevID!))
                .WhereIf(!string.IsNullOrWhiteSpace(request.DevTypeID), item => item.DevTypeID.ToString().Equals(request.DevTypeID!))
                .WhereIf(request.Status is not null, item => item.Status == request.Status)
                .WhereIf(request.CreatedBy is not null, item => item.CreatedBy == request.CreatedBy)
                .WhereIf(request.ModifiedBy is not null, item => item.ModifiedBy == request.ModifiedBy)
                .WhereIf(!string.IsNullOrWhiteSpace(request.BeginCreated) && !string.IsNullOrWhiteSpace(request.EndCreated),
                     item => (DateTime.ParseExact(item.Created, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture) >
                     DateTime.ParseExact(request.BeginCreated!, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture))
                     && (DateTime.ParseExact(request.EndCreated!, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture) >
                   DateTime.ParseExact(item.Created, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture)))
                .WhereIf(!string.IsNullOrWhiteSpace(request.BeginModified) && !string.IsNullOrWhiteSpace(request.EndModified),
                     item => (DateTime.ParseExact(item.Modified, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture) >
                     DateTime.ParseExact(request.BeginModified!, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture))
                     && (DateTime.ParseExact(request.EndModified!, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture) >
                     DateTime.ParseExact(item.Modified, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture)))
                .Count(out var count)
                .Page(request.PageIndex ?? 1, request.PageSize)
                .ToList(item => new GetDeviceInfoResponse()
                {
                    DevID = item.DevID.ToString(),
                    DevName = item.DevName,
                    DevTypeID = item.DevTypeID.ToString(),
                    Status = item.Status,
                    Created = item.Created,
                    CreatedBy = item.CreatedBy,
                    Modified = item.Modified,
                    ModifiedBy = item.ModifiedBy,
                });

            var allTypes =await DeviceCache.Instance.GetAllDevType();
            resultList.ForEach(item =>
            {
                var dID = long.Parse(item.DevTypeID);
                var myType = allTypes.FirstOrDefault(tItem => tItem.TypeID == dID);
                 
                if(myType is not null)
                {
                    item.DevTypeName = myType.TypeName;
                    item.DevTypeICON = myType.TypeICON.ToString();
                    item.PointName = myType.PointName;
                } 
            });


            return HandleData(resultList, count);
            /*
             * 
                        CacheItemSettings cacheSett = new CacheItemSettings();
                        cacheSett.SaveToAll = true;
                        var res = GCCContext.GetOrSet<string>("DevType", DeviceCache.Instance.getDevType, cacheSett).Result;
                        var deviceTypeList = System.Text.Json.JsonSerializer.Deserialize<List<DeviceTypeJson>>(res,
                             LuanNiao.JsonConverterExtends.CommonSerializerOptions.CamelCaseChineseNameCaseInsensitive);
                        Console.WriteLine("lsltest GetAllDevicesInfo deviceTypeList:{0}", deviceTypeList.Count);
                        var list = from a in deviceTypeList
                                   join b in dbres on a.TypeID equals b.DevTypeID.ToString()
                                   select new
                                   {
                                       DevID = b.DevID,
                                       DevName = b.DevName,
                                       DevTypeID = b.DevTypeID,
                                       Status = b.Status,
                                       Created = b.Created,
                                       CreatedBy = b.CreatedBy,
                                       Modified = b.Modified,
                                       ModifiedBy = b.ModifiedBy,
                                       DevTypeName = a.TypeName,
                                       DevTypeICON = a.TypeICON,
                                       PointName = a.PointName,
                                   };
                        foreach (var item in list)
                        {
                            GetDeviceInfoResponse temp = new GetDeviceInfoResponse();
                            temp.DevID = item.DevID.ToString();
                            temp.DevName = item.DevName;
                            temp.DevTypeID = item.DevTypeID.ToString();
                            temp.Status = item.Status;
                            temp.Created = item.Created;
                            temp.CreatedBy = item.CreatedBy;
                            temp.Modified = item.Modified;
                            temp.ModifiedBy = item.ModifiedBy;
                            temp.DevTypeName = item.DevTypeName;
                            temp.DevTypeICON = item.DevTypeICON;
                            temp.PointName = item.PointName;
                            resultList.Add(temp);
                        }
                        return HandleData(resultList, count);*/
        }

        [HttpGet("devinfos/search")]
        //[GCCAuth(allowOffline: true, roles: new string[] { "admin" })]
        public async Task<DataResponse<List<GetDeviceInfoResponse>>> GetDeviceInfoByPos([FromQuery] SearchDeviceInfoRequest request)
        { 
            var res = new SearchPosRet();
            var searchKey = $"POLYGON(({request.topLeft},{request.topRight},{request.bottomRight},{request.bottomLeft},{request.topLeft}))";
            var dbRESList = GCCEntrance.DBManager!.LocalReadDB!.Select<DeviceCoordinate>()
                .As("a")
                .Where(" ST_Intersects( a.Pos, ST_GeomFromText(?bbox) ) ", new
                {
                    bbox = searchKey,
                })
                .ToList();
            List<long> devIdList = new();

            foreach (var dev in dbRESList)
            {
                devIdList.Add(dev.DeviceID);
            }


            var devres = GCCEntrance.DBManager!.LocalDB!.Select<DeviceInfo>()
            .Where(item => devIdList.Contains(item.DevID))
            .ToList(item => new GetDeviceInfoResponse()
            {
                DevID = item.DevID.ToString(),
                DevName = item.DevName,
                DevTypeID = item.DevTypeID.ToString(),
                Status = item.Status,
                Created = item.Created,
                CreatedBy = item.CreatedBy,
                Modified = item.Modified,
                ModifiedBy = item.ModifiedBy
            });
            devres.ForEach(item =>
            {
                var p = dbRESList.First(pItem => pItem.DeviceID == long.Parse(item.DevID));
                item.Lat = p.Pos.Y;
                item.Lng = p.Pos.X;
            });

            /* GetDeviceInfoResponse DeviceInfoRes = new GetDeviceInfoResponse();
             DeviceInfoRes.DevID = devId.ToString();
             DeviceInfoRes.DevName = devres.DevName;
             DeviceInfoRes.DevTypeID = devres.DevTypeID.ToString();
             DeviceInfoRes.Created = devres.Created;
             DeviceInfoRes.Status = devres.Status;
             DeviceInfoRes.CreatedBy = devres.CreatedBy;
             DeviceInfoRes.Modified = devres.Modified;
             DeviceInfoRes.ModifiedBy = devres.ModifiedBy;


             CacheItemSettings cacheSett = new CacheItemSettings();
             cacheSett.SaveToAll = true;

             var result = GCCContext.GetOrSet<string>("DevType", DeviceCache.Instance.getDevType, cacheSett).Result;
             var deviceTypeList = System.Text.Json.JsonSerializer.Deserialize<List<DeviceTypeJson>>(result,
                  LuanNiao.JsonConverterExtends.CommonSerializerOptions.CamelCaseChineseNameCaseInsensitive);
             Console.WriteLine("lsltest GetDeviceInfoByPos deviceTypeList:{0}", deviceTypeList.Count);*/

            var allTypes = await DeviceCache.Instance.GetAllDevType();
            devres.ForEach(item =>
            {
                var dID = long.Parse(item.DevTypeID);
                var myType = allTypes.FirstOrDefault(tItem => tItem.TypeID == dID);

                if (myType is not null)
                {
                    item.DevTypeName = myType.TypeName;
                    item.DevTypeICON = myType.TypeICON.ToString();
                    item.PointName = myType.PointName;
                }
            });


            return HandleData(devres, devres.Count);
        }

        [HttpPost("devinfos")]
        //[GCCAuth(allowOffline: false, roles: new string[] { "admin" })]
        public DataResponse<bool> AddDeviceInfo([FromBody] List<AddDeviceInfoRequest> requestList)
        {
            if (requestList is null)
            {
                return IllegalRequest<bool>();
            }

            if (requestList.Count == 0)
            {
                return IllegalRequest<bool>();
            }
            long uid = -1;
            GCCUserInfo userInfo = GetCCUserInfo().Result;
            if (userInfo is not null)
            {
                uid = userInfo.UID;
            }
        Console.WriteLine("\nitem count:{0}\n", requestList.Count);
            var items = new List<DeviceInfo>();
            var paramItems = new List<DevParam>();
            var insertSql = new StringBuilder();
            foreach (var item in requestList)
            {
                if (string.IsNullOrWhiteSpace(item.DevName) || item.DeviceParamList.Count == 0)
                {
                    return IllegalRequest<bool>();
                }
                long deviceId = LuanNiao.Core.IDGen.GetInstance().NextId();
                items.Add(new DeviceInfo()
                {
                    DevID = deviceId,
                    DevName = item.DevName,
                    DevTypeID = long.Parse(item.DevTypeID),
                    Status = 0,
                    Created = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), 
                    CreatedBy = (int)uid,
                    ModifiedBy = (int)uid,
                    Modified = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),    
                   
                });

                /*posItems.Add(new DeviceCoordinate()
                {
                    DevID = deviceId,
                    Longitude = item.longitude,
                    Latitude = item.latitude,
                });*/

                 _ = insertSql.Append(
                                   $"INSERT INTO DevCoordinate(DeviceID,Pos) VALUES ({deviceId}" +
                                   $", ST_GeomFromText('POINT({item.longitude} {item.latitude})'));");
                foreach (var paramItem in item.DeviceParamList)
                {
                    paramItems.Add(new DevParam()
                    {
                        DevID = deviceId,
                        ParamName = paramItem.ParamName,
                        Value = paramItem.Value,
                    });
                }
            }
            var saveRes = false;
            try
            {
                if (GCCEntrance.DBManager!.LocalDB!.Insert(items).ExecuteAffrows() != items.Count)
                {
                    throw new Exception();
                }

                if (GCCEntrance.DBManager!.LocalDB!.Insert(paramItems).ExecuteAffrows() == paramItems.Count)
                {
                    _ = GCCContext.Remove("DevParams");
                }
                else
                {
                    throw new Exception();
                }

                /*if (GCCEntrance.DBManager!.LocalDB!.Insert(posItems).ExecuteAffrows() != posItems.Count)
                {
                    throw new Exception();
                }*/


                GCCEntrance.DBManager!.LocalDB!.Transaction(() =>
                {
                    _ = GCCEntrance.DBManager.LocalDB.Ado.ExecuteNonQuery(insertSql.ToString());

                });
        }
            catch (Exception ex)
            {
                throw new Exception();
            }
            saveRes = true;
            return HandleData(saveRes);
        }

        [HttpDelete("devinfos/{id}")]
        //[GCCAuth(allowOffline: false, roles: new string[] { "admin" })]
        public DataResponse<bool> deleteDevice([FromRoute] long id)
        {
            long uid = -1;
            GCCUserInfo userInfo = GetCCUserInfo().Result;
            if (userInfo is not null)
            {
                uid = userInfo.UID;
            }
            var res = GCCEntrance.DBManager!.LocalDB!.Update<DeviceInfo>()
                .Set(item => item.Status, 1)
                .Set(item => item.Modified, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                .Set(item => item.ModifiedBy, (int)uid)
                .Where(item => item.DevID == id)
                .ExecuteAffrows() == 1;
            return HandleData(res);
        }
        [HttpPut("devinfos/id/{id}")]
        //[GCCAuth(allowOffline: false, roles: new string[] { "admin" })]
        public DataResponse<bool> UpdateDevicesType([FromBody] UpdateDeviceInfoRequest request, [FromRoute] long id)
        {
            if (request is null)
            {
                return IllegalRequest<bool>();
            }
            if (string.IsNullOrWhiteSpace(request.DevName))
            {
                return InvalidParameter<bool>();
            }
            long uid = -1;
            GCCUserInfo userInfo = GetCCUserInfo().Result;
            if (userInfo is not null)
            {
                uid = userInfo.UID;
            }
            var res = GCCEntrance.DBManager!.LocalDB!.Update<DeviceInfo>()
                .Set(a => a.DevName, request.DevName)
                .Set(a => a.Status, request.Status)
                .Set(a => a.Modified, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                .Set(a => a.ModifiedBy, uid)
                .Where(a => a.DevID == id)
                .ExecuteAffrows() == 1;
            return HandleData(res);
        }
    }
}